package cn.tyz.kotlin.note

/**
 * @author : tyz
 * @ClassName: Note01
 * @Description:
 * @time 2018/5/22 22:55
 */

class Note01 {

    fun main(args: Array<String>) {
        showData() // 数据类型
        showRange() // 02区间
        showStringTemp() // 03字符串模板
        showObject() //04对象
        showArray()//05数组
    }


/**  Kotlin的数据类型包括：
    1.Double型 双精度浮点型 64位
    2.Float型 单精度浮点型 32位
    3.Long型 长整型 64位
    4.Int型 整型 32位
    5.Short 短整型 16位
    6.Byte 字节型 8位*/
    fun showData(){
        val aBoolean: Boolean = true //布尔值为真
        val anotherBoolean: Boolean = false //布尔值为假

        val aInt: Int = 8 //整型
        val anotherInt: Int = 0xFF //整型
        val binInt: Int = 0b00000011 //二进制
        val maxInt: Int = Int.MAX_VALUE //最大整型值
        val minInt: Int = Int.MIN_VALUE //最小整型值

        val aLong: Long = 5641564851251941965 //长整型
        val anotherLong: Long = 123 //长整型
        val maxLong: Long = Long.MAX_VALUE //最大长整型值
        val minLong: Long = Long.MIN_VALUE //最小长整型值

        val aFloat: Float = 2.0F //单精度浮点型
        val anotherFloat: Float = 1E3f //单精度浮点型
        val maxFloat: Float = Float.MAX_VALUE //最大单精度浮点型值
        val minFloat: Float = Float.MIN_VALUE //最小单精度浮点型值
        val minRealFloat: Float = -Float.MAX_VALUE//真正最小单精度浮点型值

        val aDouble: Double = 2.0 //双精度浮点型
        val anotherDouble: Double = 3.1415926 //双精度浮点型
        val maxDouble: Double = Double.MAX_VALUE //最大双精度浮点型值
        val minDouble: Double = Double.MIN_VALUE //最小双精度浮点型值
        val minRealDouble: Double = -Double.MAX_VALUE//真正最小双精度浮点型值

        val aShort: Short = 127 //短整型
        val maxShort: Short = Short.MAX_VALUE //最大短整型
        val minShort: Short = Short.MIN_VALUE //最小短整型

        val maxByte: Byte = Byte.MAX_VALUE //最大字节
        val minByte: Byte = Byte.MIN_VALUE //最小字节

        val aChar: Char = '0' //字符
        val bChar: Char = '中' //字符
        val cChar: Char = '\u000f' //Unicode字符


        println(minInt)
        println(Math.pow(2.0, 31.0) - 1)
        println(maxInt)
        println(-Math.pow(2.0, 31.0))
        println()

        println(maxLong)
        println(Math.pow(2.0, 63.0) - 1)
        println(minLong)
        println(-Math.pow(2.0, 63.0))
        println()

        println(aFloat)
        println(anotherFloat)
        println(maxFloat)
        println(minFloat)
        println(minRealFloat)
        println()

        println(aDouble)
        println(anotherDouble)
        println(maxDouble)
        println(minDouble)
        println(minRealDouble)
        println()

        println(aShort)
        println(maxShort)
        println(minShort)
        println()

        println(maxByte)
        println(minByte)
        println()

        println(aChar)
        println(bChar)
        println(cChar)

        println(0.0F / 0.0F) //NaN, not a num
    }

    /**02区间*/
    fun showRange(){
        val range:IntRange = 0..1024 //范围0到1024
        val range_exclusive: IntRange = 0 until 1024 //范围0到1023
        val emptyRange: IntRange = 0..-1

        println(emptyRange.isEmpty()) //判断区间是否为空
        println(range.contains(50)) //判断50是否在该区间
        println(50 in range) //判断50是否在该区间，效果与range.contains(50)一致
        for (i in range_exclusive) {
            print("$i,")
        }
    }

    /**03字符串模板*/
    fun showStringTemp(){
        val string: String = "HelloWorld" //字符串对象
        val fromChars: String = String(charArrayOf('H','e','l','l','o','W','o','r','l','d')) //由字符组成的字符串对象

        println(string == fromChars) //相当于equals方法，比较其内容
        println(string === fromChars) //比较是不是同一个对象

        val arg1: Int = 2
        val arg2: Int = 8
        println("$arg1 + $arg2 = ${arg1 + arg2}") //字符串模板

        //Hello "Jack"
        val sayHello: String = "Hello \"Jack\""
        println(sayHello) //输出转义字符

        //$salary
        println("\$salary") //输出转义字符

        //原生字符串
        val rawString: String = """
       You never like the world
       I just not so happy
    """
        println(rawString)
        println(rawString.length) //打印原生字符串的长度
    }

    // 04对象
    open class Person(var name: String, var age: Int, var hobby: String) { //抽象类
        init {
            println("新建了一个${this.javaClass.simpleName}对象,名字:$name,年龄:$age,兴趣:$hobby")
        }
    }
    class Girl(name: String, age: Int, hobby: String): Person(name, age, hobby) //继承自父类的对象应使用父类的构造器
    class Boy(name: String, age: Int, hobby: String): Person(name, age, hobby)
    fun showObject(){

        val girl: Girl = Girl("王馨", 18, "网球")
        val boy: Boy = Boy("蓝源", 22, "保龄球")
    }

    // 05数组
    fun showArray(){
        val arrayOfInt: IntArray = intArrayOf(1,3,5,7) //整型数组
        val arrayOfChar: CharArray = charArrayOf('H','e','l','l','o') //字符数组
        val arrayOfString: Array<String> = arrayOf("我","不是","简单的人") //字符串数组
        val arrayOfPerson: Array<Person> = arrayOf(Girl("王菲",22,"滑板"), Boy("田田",23,"射击")) //对象数组

        println(arrayOfInt.size) //打印出数组的大小

        for (i in arrayOfInt) { //遍历数组
            println(i)
        }

        println(arrayOfPerson[0]) //打印数组的第一个对象
        arrayOfPerson[1] = Girl("天香",33,"拳击") //修改数组的内容

        println(arrayOfChar.joinToString("")) //将数组转换成字符串

        println(arrayOfInt.slice(1..2)) //切片，获取数组中某个区间的元素
    }

    //06空安全
    fun showNull(){
        val name = getName() ?: return //名字为空时返回
        println(name?.length) //name不为空时获取长度

        val value: String? = "HelloWorld"
        println(value!!.length) //确定该值不为空时使用
    }
    fun getName(): String? {
        return null
    }

    // 07 类型转换
    fun showTypeChange(){
//        val parent: Parent = Child()
//        val parent: Parent = Parent()
//        val child: Child? = parent as Child //进行类型转换，如不成功则抛出异常
//        val child: Child? = parent as? Child //进行类型转换，如不成功返回null
//        println(child)
//
//        if (parent is Child) {
//            println(parent.name)
//        }

        val string: String? = "Hello"
        if (string is String) { //智能转换1
            println(string.length)
        }
        if (string != null) { //智能转换2
            println(string.length)
        }
        println(string!!.length) //告诉编译器当前已确定字符串不为空
    }

    //08运算符重载
    fun showOP(){
        val c1 = Complex(3.0, 4.0) //3 + 4i
        val c2 = Complex(2.0, 8.5) //2 + 8.5i

        println(c1 + c2) //5 + 12.5i
        println(c1 + 5) //8 + 9i
        println(c1 + "HelloWorld") //3

        println(c1()) //执行invoke（）方法

        val array = arrayOf("name","age","sex") //构造一个新的数组
        if ("name" in array) { //判断字符串name是否在数组中
            println(array[array.indexOf("name") + 1]) //找到字符串name在数组中的位置并打印出下一个字符串
        }
    }

    /**
     * 基本运算符
     * 1.任何类可以定义或者重载父类的基本运算符
     * 2.通过运算符对应的具名函数来定义
     * 3.对参数的个数做要求，对参数和返回值类型不做要求
     *
     * Complex表示复数
     * 参数的类型和返回值的类型不关注
     */
    class Complex(var real: Double, var imaginary: Double){
        operator fun plus(other: Complex): Complex { //operator表示操作符, plus表示加法运算, other表示传入的另一个参数
            return Complex(real + other.real, imaginary + other.imaginary)
        }

        operator fun plus(other: Int): Complex { //operator表示操作符, plus表示加法运算, other表示传入的另一个参数
            return Complex(real + other, imaginary + other)
        }

        operator fun plus(other: Any): Int { //operator表示操作符, plus表示加法运算, other表示传入的另一个参数
            return real.toInt()
        }

        operator fun invoke(): Double {
            return Math.hypot(real, imaginary)
        }

        override fun toString(): String {
            return "$real + ${imaginary}i"
        }
    }


    //09 for循环
    fun showFor(){
        var args: Array<String> = arrayOf("AAA")
        for (arg in args) { //普通for语句
            println(arg)
        }

        for ((index, value) in args.withIndex()) { //带下标和值的for语句1
            println("$index -> $value")
        }

        for (indexValue in args.withIndex()) { //带下标和值的for语句2
            println("${indexValue.index} -> ${indexValue.value}")
        }
    }

    //10 Lambda表达式
    fun showLambda(){
        var args: Array<String> = arrayOf("AAA")
        println(sum3(2,3)) //调用函数1
        println(sum3.invoke(2,3)) //调用函数2（与调用函数1一致）

        args.forEach(::println) //遍历方法1（最简单的表达方法）

        for (x in args) { //遍历方法2
            println(x)
        }

        args.forEach { //遍历方法3
            println(it)
        }

        /**
         * 遍历方法4,（与遍历方法3一致）
         * 在forEach方法中传入lambda表达式,
         * 传入参数只有一个时默认是it，也可以不写
         */
        args.forEach({ it -> println(it) })

        /**
         * 遍历方法5
         * 当最后一个参数为lambda表达式的时候，
         * 可以将遍历方法4中的的（）括号往前移
         */
        args.forEach() { println(it) }

        args.forEach {
            if (it == "q") return //此时return的是main函数，之后的The End将不会输出
            println(it)
        }

        args.forEach A@{ //给forEach起一个标签名A
            if (it == "q") return@A //结束A标签此时return的是forEach函数本身，main函数不会中断
            println(it)
        }

        println("The End")

        /**
         * 打印匿名函数时，有N参数就是实现了FunctionN接口， N的传入的参数个数
         */
        println(int2Long2)
        println(sum3)
//        println(::sum5) //打印具名函数（就是普通函数）需要在函数名前加：：, 1.2之后的版本才支持
    }



    fun sum1(a: Int, b: Int): Int { //一般函数表示
        return a + b
    }

    val int2Long2 = fun(x: Int): Long { //用常量承载匿名函数方式1
        return x.toLong()
    }

    val sum2 = { a: Int, b: Int -> a + b } //单行lambda表达式1 (Int,Int) -> Int

    val printHello = { println("This is it") } //单行lambda表达式2 () -> Unit

    val sum3 = { //多行lambda表达式
        arg1: Int, arg2: Int ->
        //参数
        println("$arg1 + $arg2 = ${arg1 + arg2}") //执行过程打印消息
        arg1 + arg2 //返回值
    } // (Int,Int) -> Int


//   11 when表达式
    fun showWhen(){
        var args: Array<String> = arrayOf("AAA")
        val x = 5
        when (x) {
            is Int -> println("Hello $x")
            in 1..100 -> println("$x is in 1..100")
            !in 1..100 -> println("$x in not in 1..100")
            args[0].toInt() -> println("x == args[0]")
        }

        val mode = when {
            args.isNotEmpty() && args[0] == "1" -> 1
            else -> 0
        }
    }

    // 12 while
    fun showWhile(){
        var x = 5
        while (x > 0) { //while循环
            println(x)
            x--
        }

        do { //do...while循环
            println(x)
            x--
        } while (x > 0)
    }

    //13 中缀表达式, 自定义运算符
    fun showInfix(){
        class Book {
            infix fun on(any: Any): Boolean { //infix表示中缀表达式，定义了on表达关键字，原本是没有的
                return false
            }
        }

        class Desk

        if (Book() on Desk()) { //dsl中常用，自定义运算符on

        }
    }

    /**
     * 14具名参数：在使用函数的时候，把参数名写上，
     * 参数名的顺序可交换，但只要其中一个写上参数名，其他的就必须写上
     */
    fun show(){
        println(sum5(x = 4, y = 5))
        println(sum5(y = 2, x = 4))
    }
    fun sum5(x: Int, y: Int): Int = x + y



    /**
     * 15 函数
     * 编写函数注意事项
     * 1.功能要单一
     * 2.函数名要做到顾名思义
     * 3.参数个数不要太多
     * 普通函数也叫具名函数，也就是有具体名称的函数
     * 函数的默认返回值为Unit类型，返回值带其他的类型的需要在参数的括号后加冒号并指定返回值类型
     */
}